#include "markdownrenderer.h"
#include <QDebug>
#include <QFile>
#include <QTextStream>
#include <QRegularExpression>
#include <QElapsedTimer>

MarkdownRenderer::MarkdownRenderer(QObject *parent) : QObject(parent),
    m_workerThread(new QThread(this)),
    m_cancelRequested(false),
    m_currentTheme("light")
{
    // 将当前对象移动到工作线程
    moveToThread(m_workerThread);
    connect(m_workerThread, &QThread::finished, this, &QObject::deleteLater);
    connect(this, &MarkdownRenderer::renderInThread, this, &MarkdownRenderer::handleRenderInThread);
    m_workerThread->start();
}

MarkdownRenderer::~MarkdownRenderer()
{
    // 请求取消当前渲染
    cancel();
    // 停止工作线程
    m_workerThread->quit();
    m_workerThread->wait();
}

void MarkdownRenderer::render(const QString &text, const QString &theme)
{
    QMutexLocker locker(&m_mutex);
    m_cancelRequested = false;
    m_currentTheme = theme;
    emit renderInThread(text, theme);
}

void MarkdownRenderer::cancel()
{
    QMutexLocker locker(&m_mutex);
    m_cancelRequested = true;
}

void MarkdownRenderer::handleRenderInThread(const QString &text, const QString &theme)
{
    QElapsedTimer timer;
    timer.start();

    // 检查是否取消请求
    if (m_cancelRequested) {
        emit renderingFinished("<p>Rendering cancelled</p>");
        return;
    }

    // 解析Markdown文本
    const char *markdownText = text.toUtf8().constData();
    cmark_node *root = cmark_parse_document(markdownText, strlen(markdownText), CMARK_OPT_DEFAULT);

    if (!root) {
        emit renderingFinished("<p>Error parsing Markdown</p>");
        return;
    }

    // 检查是否取消请求
    if (m_cancelRequested) {
        cmark_node_free(root);
        emit renderingFinished("<p>Rendering cancelled</p>");
        return;
    }

    // 渲染节点为HTML
    QString content = renderNode(root, theme);
    cmark_node_free(root);

    // 检查是否取消请求
    if (m_cancelRequested) {
        emit renderingFinished("<p>Rendering cancelled</p>");
        return;
    }

    // 生成完整HTML
    QString html = initHtmlTemplate(theme) + content + "</body></html>";

    // 发送渲染完成信号
    emit renderingFinished(html);
    emit renderingProgress(100);

    qDebug() << "Rendering completed in" << timer.elapsed() << "ms";
}

QString MarkdownRenderer::renderNode(cmark_node *node, const QString &theme)
{
    if (!node || m_cancelRequested) return QString();

    QString html;
    cmark_node_type nodeType = cmark_node_get_type(node);
    cmark_node *child = cmark_node_first_child(node);

    switch (nodeType) {
        case CMARK_NODE_DOCUMENT:
            while (child) {
                html += renderNode(child, theme);
                child = cmark_node_next(child);
            }
            break;

        case CMARK_NODE_BLOCK_QUOTE:
            html += "<blockquote>\n";
            while (child) {
                html += renderNode(child, theme);
                child = cmark_node_next(child);
            }
            html += "</blockquote>\n";
            break;

        case CMARK_NODE_LIST:
            {
                QString tag = cmark_node_get_list_type(node) == CMARK_ORDERED_LIST ? "ol" : "ul";
                int start = cmark_node_get_list_start(node);
                html += QString("<%1%2>\n").arg(tag).arg(start > 1 ? QString(" start=\"%1\"").arg(start) : "");
                while (child) {
                    html += renderNode(child, theme);
                    child = cmark_node_next(child);
                }
                html += QString("</%1>\n").arg(tag);
            }
            break;

        case CMARK_NODE_ITEM:
            html += "<li>\n";
            while (child) {
                html += renderNode(child, theme);
                child = cmark_node_next(child);
            }
            html += "</li>\n";
            break;

        case CMARK_NODE_CODE_BLOCK:
            {
                QString info = QString::fromUtf8(cmark_node_get_fence_info(node));
                QString text = QString::fromUtf8(cmark_node_get_literal(node));
                html += renderCodeBlock(text, info.split(' ').first(), theme);
            }
            break;

        case CMARK_NODE_HTML_BLOCK:
            html += QString::fromUtf8(cmark_node_get_literal(node)) + "\n";
            break;

        case CMARK_NODE_PARAGRAPH:
            html += "<p>\n";
            while (child) {
                html += renderNode(child, theme);
                child = cmark_node_next(child);
            }
            html += "</p>\n";
            break;

        case CMARK_NODE_HEADING:
            {
                int level = cmark_node_get_heading_level(node);
                html += QString("<h%1>\n").arg(level);
                while (child) {
                    html += renderNode(child, theme);
                    child = cmark_node_next(child);
                }
                html += QString("</h%1>\n").arg(level);
            }
            break;

        case CMARK_NODE_THEMATIC_BREAK:
            html += "<hr/>\n";
            break;

        case CMARK_NODE_TEXT:
            html += QString::fromUtf8(cmark_node_get_literal(node)).toHtmlEscaped();
            break;

        case CMARK_NODE_SOFTBREAK:
            html += "<br/>\n";
            break;

        case CMARK_NODE_LINEBREAK:
            html += "<br/>\n";
            break;

        case CMARK_NODE_CODE:
            html += QString("<code>%1</code>").arg(
                QString::fromUtf8(cmark_node_get_literal(node)).toHtmlEscaped());
            break;

        case CMARK_NODE_HTML_INLINE:
            html += QString::fromUtf8(cmark_node_get_literal(node));
            break;

        case CMARK_NODE_EMPH:
            html += "<em>";
            while (child) {
                html += renderNode(child, theme);
                child = cmark_node_next(child);
            }
            html += "</em>";
            break;

        case CMARK_NODE_STRONG:
            html += "<strong>";
            while (child) {
                html += renderNode(child, theme);
                child = cmark_node_next(child);
            }
            html += "</strong>";
            break;

        case CMARK_NODE_LINK:
            {
                QString url = QString::fromUtf8(cmark_node_get_url(node)).toHtmlEscaped();
                QString title = QString::fromUtf8(cmark_node_get_title(node)).toHtmlEscaped();
                html += QString("<a href=\"%1\"%2>").arg(url).arg(title.isEmpty() ? "" : QString(" title=\"%1\"").arg(title));
                while (child) {
                    html += renderNode(child, theme);
                    child = cmark_node_next(child);
                }
                html += "</a>";
            }
            break;

        case CMARK_NODE_IMAGE:
            {
                QString url = QString::fromUtf8(cmark_node_get_url(node)).toHtmlEscaped();
                QString title = QString::fromUtf8(cmark_node_get_title(node)).toHtmlEscaped();
                QString alt = QString();
                cmark_node *altChild = cmark_node_first_child(node);
                if (altChild && cmark_node_get_type(altChild) == CMARK_NODE_TEXT) {
                    alt = QString::fromUtf8(cmark_node_get_literal(altChild)).toHtmlEscaped();
                }
                html += QString("<img src=\"%1\" alt=\"%2\"%3 class=\"markdown-image\"/>").
                    arg(url).arg(alt).arg(title.isEmpty() ? "" : QString(" title=\"%1\"").arg(title));
            }
            break;

        default:
            qDebug() << "Unhandled node type:" << nodeType;
            break;
    }

    // 检查是否取消请求
    if (m_cancelRequested) {
        html = "<p>Rendering cancelled</p>";
    }

    return html;
}

QString MarkdownRenderer::renderCodeBlock(const QString &text, const QString &language, const QString &theme)
{
    Q_UNUSED(theme);

    // 如果没有指定语言，使用通用代码块
    if (language.isEmpty()) {
        return QString("<pre><code class=\"language-none\">%1</code></pre>\n").
            arg(text.toHtmlEscaped());
    }

    // 为支持的语言应用语法高亮
    return QString("<pre><code class=\"language-%1\">%2</code></pre>\n").
        arg(language.toLower()).arg(text.toHtmlEscaped());
}

QString MarkdownRenderer::getHighlightCss(const QString &theme)
{
    // 根据主题返回不同的代码高亮CSS
    if (theme == "dark") {
        return R"(
<style>
pre code {
    background-color: #1e1e1e;
    color: #d4d4d4;
    border-radius: 6px;
    padding: 1em;
    display: block;
    overflow-x: auto;
}

/* 代码高亮样式 - 深色主题 */
.hljs-keyword { color: #569cd6; }
.hljs-constant { color: #4ec9b0; }
.hljs-string { color: #ce9178; }
.hljs-comment { color: #6a9955; }
.hljs-function { color: #dcdcaa; }
.hljs-type { color: #4ec9b0; }
.hljs-variable { color: #9cdcfe; }
.hljs-operator { color: #d4d4d4; }
.hljs-punctuation { color: #d4d4d4; }
.hljs-property { color: #9cdcfe; }
.hljs-number { color: #b5cea8; }
.hljs-boolean { color: #569cd6; }
.hljs-array { color: #b5cea8; }
.hljs-regex { color: #d16969; }
.hljs-import { color: #c586c0; }
.hljs-class { color: #4ec9b0; }
.hljs-method { color: #dcdcaa; }
</style>
        )";
    } else {
        return R"(
<style>
pre code {
    background-color: #f6f8fa;
    color: #333;
    border-radius: 6px;
    padding: 1em;
    display: block;
    overflow-x: auto;
}

/* 代码高亮样式 - 浅色主题 */
.hljs-keyword { color: #0033b3; }
.hljs-constant { color: #006666; }
.hljs-string { color: #067d17; }
.hljs-comment { color: #008000; }
.hljs-function { color: #7d5bbf; }
.hljs-type { color: #006666; }
.hljs-variable { color: #001080; }
.hljs-operator { color: #393a34; }
.hljs-punctuation { color: #393a34; }
.hljs-property { color: #001080; }
.hljs-number { color: #1750eb; }
.hljs-boolean { color: #0033b3; }
.hljs-array { color: #1750eb; }
.hljs-regex { color: #0e7c6b; }
.hljs-import { color: #7d5bbf; }
.hljs-class { color: #006666; }
.hljs-method { color: #7d5bbf; }
</style>
        )";
    }
}

QString MarkdownRenderer::initHtmlTemplate(const QString &theme)
{
    // 基础HTML结构和样式
    return QString(R"(
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Markdown Preview</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
            line-height: 1.6;
            margin: 0 auto;
            padding: 20px;
            max-width: 800px;
            color: %1;
            background-color: %2;
        }

        h1, h2, h3, h4, h5, h6 {
            margin-top: 1.5em;
            margin-bottom: 0.5em;
            font-weight: 600;
        }

        h1 { font-size: 1.8em; border-bottom: 1px solid %3; padding-bottom: 0.3em; }
        h2 { font-size: 1.5em; border-bottom: 1px solid %3; padding-bottom: 0.3em; }
        h3 { font-size: 1.3em; }
        h4 { font-size: 1.2em; }
        h5 { font-size: 1.1em; }
        h6 { font-size: 1em; color: %4; }

        p { margin-top: 0; margin-bottom: 1em; }

        ul, ol {
            margin-top: 0; margin-bottom: 1em;
            padding-left: 2em;
        }

        li { margin-bottom: 0.5em; }

        blockquote {
            border-left: 4px solid %3;
            padding-left: 1em;
            margin-left: 0;
            color: %4;
            font-style: italic;
        }

        a {
            color: #0066cc;
            text-decoration: none;
        }

        a:hover { text-decoration: underline; }

        img.markdown-image {
            max-width: 100%;
            height: auto;
            border-radius: 4px;
            margin: 1em 0;
        }

        pre {
            margin-top: 0; margin-bottom: 1em;
        }

        table {
            border-collapse: collapse;
            margin: 1em 0;
            width: 100%;
        }

        th, td {
            border: 1px solid %3;
            padding: 0.5em 1em;
            text-align: left;
        }

        th {
            background-color: %5;
            font-weight: 600;
        }

        tr:nth-child(even) { background-color: %6; }
    </style>
    %7
    <script src="https://cdn.jsdelivr.net/npm/highlight.js@11.5.1/lib/highlight.min.js"></script>
    <script>hljs.highlightAll();</script>
</head>
<body>
)").
        arg(theme == "dark